package util.ranker;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;

import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException;

import util.hashing.Sorting;
import util.ir.LMSearcher;
import util.models.LanguageModel;

public class TagRanking {

	public static String bigram_index = "/home/sergio/delicious_index/trigrams_index_filter2";
	public static String trigram_index = "/home/sergio/delicious_index/trigrams_index_filter2";

	float lambda = 0.9f;

	/**
	 * Receives tags representing the query The seed tags
	 * 
	 * Output
	 * 
	 */

	Hashtable<String, Float> seed_tags = new Hashtable<String, Float>();
	LMSearcher trigram_searcher = null;
	LMSearcher bigram_searcher = null;

	private LanguageModel lm = new LanguageModel();

	public TagRanking(LMSearcher trigram_searcher, LMSearcher bigram_searcher) throws IOException {

		// trigram_searcher = new LMSearcher(trigram_index);
		this.trigram_searcher = trigram_searcher;
		this.bigram_searcher= bigram_searcher;
		
	}

	
	
	
	public void init(Hashtable<String, Float> t_tags,	Hashtable<String, Float> seed_tags) throws CorruptIndexException,
			IOException, ParseException {
		initLanguageModel(t_tags);

		if (seed_tags != null) {
			initSeedTags(seed_tags);
		}

	}

	public void initLanguageModel(Hashtable<String, Float> t_tags)
			throws CorruptIndexException, IOException, ParseException {

		Enumeration<String> keys = t_tags.keys();

		HashSet<String> query = new HashSet<String>();
		while (keys.hasMoreElements()) {

			String t = keys.nextElement();
			query.add(t);

		}

		trigram_searcher.trigramSearchLM(query, lm);
		bigram_searcher.bigramSearchLM(query, lm); //check this, is it neccesary?

	}
	
	
	public void initSeedTags(Hashtable<String, Float> s_tags)
			throws CorruptIndexException, IOException, ParseException {

		Enumeration<String> keys = s_tags.keys();

		
		while (keys.hasMoreElements()) {
			
			String seed = keys.nextElement();
			
			float val = s_tags.get(seed);
			
			seed_tags.put(seed, val);
			

		}

		
	}
	

	public  Iterator<Entry<String, Float>>  rankSuggestions() {

		/*
		 * For each candidate tag S
		 */

		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		Enumeration<String> s_enum = lm.trigrams.keys();

		while (s_enum.hasMoreElements()) {
			
			String s = s_enum.nextElement();

			/*
			 * Group by k
			 */

			Hashtable<String, Hashtable<String, Integer>> bi = lm.trigrams
					.get(s);

			float score = aggregate_b(s, bi);
			
			scores.put(s, score);

		}

		Iterator<Entry<String, Float>> tuples = Sorting.sortHashNumericValues(scores, false);

		scores.clear();
		scores = null;
		
		return tuples;
	}

	private float aggregate_b(String s,
			Hashtable<String, Hashtable<String, Integer>> bi) {

		float total = 0f;
		Enumeration<String> k_enum = bi.keys();
		while (k_enum.hasMoreElements()) {

			String k = k_enum.nextElement();

			Hashtable<String, Integer> uni = bi.get(k);
			float score_k = aggregate_c(s, k, uni);

			float weight_k = 1f;

			if (seed_tags.containsKey(k)) {
				weight_k = seed_tags.get(k);
			}
			weight_k = 1f;
			score_k = score_k * weight_k;
			total = total + score_k;

		}

		return total;
	}

	private float aggregate_c(String s, String k, Hashtable<String, Integer> uni) {
		// TODO Auto-generated method stub

		Enumeration<String> t_enum = uni.keys();
		float total = 0f;
		while (t_enum.hasMoreElements()) {

			/**
			 * 
			 * For each t in k given s
			 * 
			 */
			String t = t_enum.nextElement();

			// Score for t tag
			float score = score_tag(s, k, t, lambda);

			total = total + score;

		}

		return total;

	}

	private float score_tag(String s, String k, String t, float lambda) {
		// TODO Auto-generated method stub

		float freq_skt = lm.getTrigramFreq(s, k, t);

		float freq_sk = lm.getBigramFreq(s, k);

		/**
		 * let's try smoothing
		 * 
		 * 
		 */

		float freq_kt = lm.getBigramFreq(k, t);
		float freq_k = lm.getUnigramFreq(k);

		float score = lambda * freq_skt / freq_sk + (1 - lambda) * freq_kt
				/ freq_k;
		//System.out.println(freq_skt + "\t" + freq_kt + "\t" + freq_k + "\t"	+ score);
		return (float) Math.log(score);
	}

	public void clean() {

		lm.trigrams.clear();
		lm.bigrams.clear();
		lm.unigrams.clear();
		// seed_tags.clear();

		lm = null;
		
		
		

	}

	public static void main(String args[]) throws IOException, ParseException {
		LMSearcher trigram_searcher = new LMSearcher(trigram_index);
		LMSearcher bigram_searcher = new LMSearcher(bigram_index);
		TagRanking ranker = new TagRanking(trigram_searcher, bigram_searcher);

		Hashtable<String, Float> query = new Hashtable<String, Float>();
		query.put("games", 1f);
		query.put("game", 1f);
		query.put("toys", 1f);
		query.put("free", 1f);
		query.put("flash", 1f);
		query.put("coloring", 1f);
		query.put("social", 1f);

		ranker.initLanguageModel(query);
		Iterator<Entry<String, Float>> scores = null;
		
		
		scores =ranker.rankSuggestions();
		
		System.out.println(scores.toString());

	}

}
